package org.jiamandan.com.config;

import cn.hutool.extra.spring.SpringUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.jiamandan.com.constant.BizConstant;

import java.net.InetSocketAddress;
import java.nio.ByteOrder;
import java.util.concurrent.TimeUnit;

/**
 * Netty Channel 初始化器
 * 配置读超时、写超时、读写超时
 */
@Slf4j
public class NettyChannelInitializer extends ChannelInitializer<Channel> {

    private static final NettyProperties nettyProperties;

    static {
        nettyProperties = SpringUtil.getBean(NettyProperties.class);
    }

    @Override
    protected void initChannel(Channel channel) throws Exception {
        configureChannel(channel);
    }

    private void configureChannel(Channel channel) {
        InetSocketAddress socketAddress = (InetSocketAddress) channel.localAddress();
        ChannelPipeline pipeline = channel.pipeline();
        int port = socketAddress.getPort();

        // 配置空闲检测 - 这是最重要的部分
        configureIdleHandler(pipeline, port);

        // 根据端口配置不同的协议处理器
        if (port == BizConstant.HardSoftFactoryPort.JSY_XIN || port == 18083) {
            configureJsyHandlers(pipeline);
        } else if (port == 18080 || port == 18082) {
            configureTcpHandlers(pipeline);
        } else {
            // 默认TCP配置
            configureTcpHandlers(pipeline);
        }

        // 添加业务逻辑处理器
        pipeline.addLast("tcpInboundAdapter", new TcpInboundAdapter());
    }

    /**
     * 配置空闲检测处理器
     * @param pipeline Channel管道
     * @param port 端口号
     */
    private void configureIdleHandler(ChannelPipeline pipeline, int port) {
        // 从配置中获取超时时间
        int readerIdleTime = nettyProperties.getReaderIdleTime();
        int writerIdleTime = nettyProperties.getWriterIdleTime();
        int allIdleTime = nettyProperties.getAllIdleTime();

        // 是否启用心跳检测
        boolean enableHeartbeat = nettyProperties.getEnableHeartbeat() != null ?
                                  nettyProperties.getEnableHeartbeat() : true;

        if (!enableHeartbeat) {
            log.info("端口 {} 心跳检测已禁用", port);
            return;
        }

        // 根据不同端口可以设置不同的超时策略
        if (port == 18085) {
            // UDP端口可能需要更短的超时时间
            readerIdleTime = readerIdleTime > 0 ? Math.min(readerIdleTime, 30) : 30;
        }

        log.info("端口 {} 配置空闲检测 - 读超时: {}秒, 写超时: {}秒, 读写超时: {}秒",
                 port, readerIdleTime, writerIdleTime, allIdleTime);

        /**
         * IdleStateHandler 参数说明：
         * 1. readerIdleTimeSeconds: 读超时时间（秒），0表示不检测
         * 2. writerIdleTimeSeconds: 写超时时间（秒），0表示不检测
         * 3. allIdleTimeSeconds: 读写都空闲的超时时间（秒），0表示不检测
         * 4. unit: 时间单位
         *
         * 触发条件：
         * - READER_IDLE: 在指定时间内没有读操作
         * - WRITER_IDLE: 在指定时间内没有写操作
         * - ALL_IDLE: 在指定时间内既没有读也没有写操作
         */
        pipeline.addLast("idleStateHandler",
            new IdleStateHandler(
                readerIdleTime,   // 读超时
                writerIdleTime,   // 写超时
                allIdleTime,      // 读写超时
                TimeUnit.SECONDS
            )
        );

        // 添加自定义的空闲事件处理器
        pipeline.addLast("idleEventHandler", new NettyIdleEventHandler());
    }

    /**
     * 配置JSY协议处理器（基于文本协议）
     */
    private void configureJsyHandlers(ChannelPipeline pipeline) {
        ByteBuf delimiter = Unpooled.copiedBuffer("\r\n".getBytes());
        pipeline.addLast("frameDecoder", new DelimiterBasedFrameDecoder(2048, delimiter));
        pipeline.addLast("stringDecoder", new StringDecoder());
        pipeline.addLast("stringEncoder", new StringEncoder());
        log.debug("配置JSY文本协议处理器");
    }

    /**
     * 配置TCP二进制协议处理器
     */
    private void configureTcpHandlers(ChannelPipeline pipeline) {
        // 自定义解码器
        pipeline.addLast("nettyDecoder",
            new NettyDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 1, 3, 2, 1, 2, 0, 0, true));

        // 日志处理器（仅在错误时记录）
        pipeline.addLast("loggingHandler", new LoggingHandler(LogLevel.ERROR));

        // 字节数组编解码器
        pipeline.addLast("byteArrayEncoder", new ByteArrayEncoder());
        pipeline.addLast("byteArrayDecoder", new ByteArrayDecoder());

        log.debug("配置TCP二进制协议处理器");
    }
}